﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using YJKArchUtils.Utils;
using YJKGeometryFuncs;
using YJKGeometryFuncs.CurveUtility;
using YJKPatternSign.StairsRoomPlanSign.ControlLayer;

namespace YJKPatternSign.StairsRoomPlanSign.ModelLayer
{
	public class StairsRunPacker : BaseShapePacker
	{
		public StairsRun ThisStairsRun
		{
			get
			{
				return this.m_thisStairsRun;
			}
			private set
			{
				this.m_thisStairsRun = value;
			}
		}

		public List<XYZ> LstDriection
		{
			get
			{
				return this.m_lstDriection;
			}
			private set
			{
				this.m_lstDriection = value;
			}
		}

		public List<Curve> LstUsePath
		{
			get
			{
				return this.m_lstUsePath;
			}
			private set
			{
				this.m_lstUsePath = value;
			}
		}

		public double StartElevation
		{
			get
			{
				return this.m_dStartElevation;
			}
			private set
			{
				this.m_dStartElevation = value;
			}
		}

		public double EndElevation
		{
			get
			{
				return this.m_dEndElevation;
			}
			private set
			{
				this.m_dEndElevation = value;
			}
		}

		public double MidElevation
		{
			get
			{
				return this.m_dMidElevation;
			}
			private set
			{
				this.m_dMidElevation = value;
			}
		}

		public string RunText
		{
			get
			{
				return this.m_strRunText;
			}
			private set
			{
				this.m_strRunText = value;
			}
		}

		public string CutRunText
		{
			get
			{
				return this.m_strCutRunText;
			}
			private set
			{
				this.m_strCutRunText = value;
			}
		}

		public bool IfUpStairsRun
		{
			get
			{
				return this.m_bIfUpStairsRun;
			}
			private set
			{
				this.m_bIfUpStairsRun = value;
			}
		}

		private ViewData UseViewData
		{
			get
			{
				return this.m_UseViewData;
			}
			set
			{
				this.m_UseViewData = value;
			}
		}

		public StairPlanDataPacker UseStairPlanData
		{
			get
			{
				return this.m_useStairPlanData;
			}
			set
			{
				this.m_useStairPlanData = value;
			}
		}

		public int ViewRunCount
		{
			get
			{
				return this.m_nViewRunCount;
			}
			private set
			{
				this.m_nViewRunCount = value;
			}
		}

		public List<FlatRoofPacker> LstLinkFlatRoofPackerWithThis
		{
			get
			{
				return this.m_lstLinkFlatRoofPackerWithThis;
			}
			private set
			{
				this.m_lstLinkFlatRoofPackerWithThis = value;
			}
		}

		public StairsRunPacker(StairsRun inputStairsRun, StairPlanDataPacker inputDataPacker, RevitLinkInstance inputLinkInstance = null) : base(inputStairsRun, StairsRunPacker.GetStairsRunCurves(inputStairsRun, inputLinkInstance))
		{
			this.m_thisLinkInstance = inputLinkInstance;
			this.ThisStairsRun = inputStairsRun;
			Transform transform = null;
			if (inputLinkInstance != null)
			{
				transform = inputLinkInstance.GetTransform();
			}
			this.UseStairPlanData = inputDataPacker;
			this.UseViewData = inputDataPacker.UseViewData;
			this.LstUsePath.AddRange(Utility.GetListTransformCurve(this.ThisStairsRun.GetStairsPath().ToList<Curve>(), transform));
			this.LstUsePath = Utility.ChangeLstCurveZ(this.LstUsePath, SignManger.ThisStairPlandDataPacker.NowViewZ);
			foreach (Curve curve in this.LstUsePath)
			{
				this.LstDriection.Add((curve.GetEndPoint(1) - curve.GetEndPoint(0)).Normalize());
			}
			double z = YJKGeometryFuncs.Geometry.TransformPoint(inputStairsRun.get_BoundingBox(null).Min, transform).Z;
			this.EndElevation = z + this.ThisStairsRun.TopElevation;
			this.StartElevation = z + this.ThisStairsRun.BaseElevation;
			this.MidElevation = (this.EndElevation + this.StartElevation) / 2.0;
			this.IfUpStairsRun = true;
		}

		public override void UpdataThisShapeByView(ViewData inputData)
		{
			if (this.EndElevation < inputData.CutHeightZ)
			{
				base.ViewKind = ShapeViewKindEnum.Total;
				this.ViewRunCount = this.ThisStairsRun.ActualTreadsNumber;
				this.RunText = this.GetRunShapeDesText(false);
				return;
			}
			if (!YJKGeometryFuncs.Geometry.LessThan(this.StartElevation, inputData.CutHeightZ))
			{
				base.ViewKind = ShapeViewKindEnum.None;
				this.ViewRunCount = 0;
				return;
			}
			base.ViewKind = ShapeViewKindEnum.Cut;
			this.UpdataViewKindByInput(inputData.CutHeightZ, true);
		}

		public void UpdataViewKindByInput(double inputElevation, bool ifFromStart)
		{
			if (!ifFromStart && YJKGeometryFuncs.Geometry.Lessthan_Or_Equal(this.EndElevation, inputElevation))
			{
				return;
			}
			if (ifFromStart && YJKGeometryFuncs.Geometry.Lessthan_Or_Equal(inputElevation, this.StartElevation))
			{
				return;
			}
			this.viewKind = ShapeViewKindEnum.Cut;
			List<XYZ> list = new List<XYZ>();
			base.LstAllCutedCurve = new List<Curve>();
			double num;
			XYZ xyz;
			if (ifFromStart)
			{
				num = inputElevation - this.StartElevation;
				XYZ endPoint = this.LstUsePath[0].GetEndPoint(0);
				base.LstAllCutedCurve.Add(StairsRunPacker.GetNearLine(endPoint, base.LstAllShapeCurve));
				xyz = this.LstDriection[0].Normalize();
			}
			else
			{
				num = this.EndElevation - inputElevation;
				XYZ endPoint = this.LstUsePath[0].GetEndPoint(1);
				base.LstAllCutedCurve.Add(StairsRunPacker.GetNearLine(endPoint, base.LstAllShapeCurve));
				xyz = -this.LstDriection[0].Normalize();
			}
			double num2 = num / this.ThisStairsRun.GetStairs().ActualRiserHeight;
			double num3;
			if (ifFromStart)
			{
				num3 = (Math.Floor(num2) - 1.0) * this.ThisStairsRun.GetStairs().ActualTreadDepth;
				this.ViewRunCount = (int)Math.Floor(num2) - 1;
			}
			else
			{
				num3 = Math.Ceiling(num2) * this.ThisStairsRun.GetStairs().ActualTreadDepth;
				this.ViewRunCount = (int)Math.Ceiling(num2);
			}
			list.Add(base.LstAllCutedCurve[0].GetEndPoint(0).Add(xyz * num3));
			list.Add(base.LstAllCutedCurve[0].GetEndPoint(1).Add(xyz * num3));
			base.LstAllCutedCurve.Add(Line.CreateBound(base.LstAllCutedCurve[0].GetEndPoint(0), list[0]));
			base.LstAllCutedCurve.Add(Line.CreateBound(list[0], list[1]));
			base.LstAllCutedCurve.Add(Line.CreateBound(list[1], base.LstAllCutedCurve[0].GetEndPoint(1)));
			this.RunText = this.GetRunShapeDesText(ifFromStart);
		}

		public bool IfShadowInputStairs(StairsRunPacker inputStairsRun)
		{
			bool result = false;
			if (inputStairsRun.EndElevation < this.EndElevation)
			{
				result = CurveUtility.IsPointInArea(base.LstAllShapeCurve, new XYZ(inputStairsRun.MidPoint.X, inputStairsRun.MidPoint.Y, inputStairsRun.UseViewData.CutHeightZ));
			}
			return result;
		}

		public Curve GetStairRunEndCurve(int inputIndex, bool ifInCutedShape)
		{
			Curve curve = null;
			Line stairRunMidLine = this.GetStairRunMidLine(ifInCutedShape);
			List<Curve> list = new List<Curve>();
			if (ifInCutedShape)
			{
				list.AddRange(base.LstAllCutedCurve);
			}
			else
			{
				list.AddRange(base.LstAllShapeCurve);
			}
			if (inputIndex == 2)
			{
				XYZ averticalVector = Utility.GetAVerticalVector(this.LstDriection[0], false);
				Line.CreateUnbound(base.MidPoint, averticalVector);
				List<XYZ> list2 = new List<XYZ>();
				IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
				foreach (Curve curve2 in list)
				{
                    if ((int)curve.Intersect(curve2, out intersectionResultArray) == 8)
					{
						list2.Add(intersectionResultArray.get_Item(0).XYZPoint);
					}
				}
				curve = Line.CreateBound(list2[0], list2[1]);
			}
			else
			{
				curve = StairsRunPacker.GetNearLine(stairRunMidLine.GetEndPoint(inputIndex), list);
			}
			return curve;
		}

		public static Curve GetNearLine(XYZ point, List<Curve> LstCurve)
		{
			Curve result = null;
			double num = double.MaxValue;
			foreach (Curve curve in LstCurve)
			{
				if (curve.Distance(point) < num)
				{
					num = curve.Distance(point);
					result = curve;
				}
			}
			return result;
		}

		public Line GetStairRunMidLine(bool ifInCutedShape)
		{
			Line line = this.LstUsePath[0] as Line;
			if (ifInCutedShape)
			{
				List<XYZ> list = new List<XYZ>();
				Line line2 = line.Clone() as Line;
				line2.MakeUnbound();
				IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
				using (List<Curve>.Enumerator enumerator = base.LstAllCutedCurve.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
                        if ((int)enumerator.Current.Intersect(line2, out intersectionResultArray) == 8)
						{
							list.Add(intersectionResultArray.get_Item(0).XYZPoint);
						}
					}
				}
				line = Line.CreateBound(StairsRunPacker.GetADirectionPoint(list, line2, true), StairsRunPacker.GetADirectionPoint(list, line2, false));
			}
			return line;
		}

		private static XYZ GetADirectionPoint(List<XYZ> points, Line path, bool ifAtStart)
		{
			if (ifAtStart)
			{
				return path.Evaluate(Math.Min(path.Project(points[0]).Parameter, path.Project(points[1]).Parameter), false);
			}
			return path.Evaluate(Math.Max(path.Project(points[0]).Parameter, path.Project(points[1]).Parameter), false);
		}

		public string GetRunShapeDesText(bool ifInCutedShape)
		{
			double num = Common.FeetToMM(this.ThisStairsRun.GetStairs().ActualTreadDepth);
			string result;
			if (ifInCutedShape)
			{
				double num2 = num * (double)this.ViewRunCount;
				result = string.Concat(new object[]
				{
					num.ToString(),
					"×",
					this.ViewRunCount,
					"=",
					num2
				});
			}
			else
			{
				double num3 = Math.Floor(num * (double)this.ThisStairsRun.ActualTreadsNumber);
				result = string.Concat(new object[]
				{
					Math.Ceiling(num),
					"×",
					this.ThisStairsRun.ActualTreadsNumber,
					"=",
					num3
				});
			}
			return result;
		}

		private static List<Curve> GetStairsRunCurves(StairsRun inputStairsRun, RevitLinkInstance inputLinkInstance)
		{
			List<Curve> list = new List<Curve>();
			Transform transform = null;
			if (inputLinkInstance != null)
			{
				transform = inputLinkInstance.GetTransform();
			}
			if (transform != null)
			{
				list.AddRange(Utility.GetListTransformCurve(inputStairsRun.GetFootprintBoundary().ToList<Curve>(), transform));
			}
			else
			{
				list.AddRange(inputStairsRun.GetFootprintBoundary().ToList<Curve>());
			}
			return list;
		}

		private StairsRun m_thisStairsRun;

		private RevitLinkInstance m_thisLinkInstance;

		private List<XYZ> m_lstDriection = new List<XYZ>();

		private List<Curve> m_lstUsePath = new List<Curve>();

		private double m_dStartElevation;

		private double m_dEndElevation;

		private double m_dMidElevation;

		private string m_strRunText = "";

		private string m_strCutRunText = "";

		private bool m_bIfUpStairsRun = true;

		private ViewData m_UseViewData;

		private StairPlanDataPacker m_useStairPlanData;

		private int m_nViewRunCount;

		private List<FlatRoofPacker> m_lstLinkFlatRoofPackerWithThis = new List<FlatRoofPacker>
		{
			null,
			null
		};
	}
}
